Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / backend / web_audio_bridge.py

Displaying Raw • Download


meshchatx/src/backend/web_audio_bridge.py 6a4ed6a04836dce34d43b43e7e3512705342c086 (6a4ed6a0) Text, 8.45 KB

Tff7b72import T7ee787asyncio
Tff7b72import T7ee787json
Tff7b72import T7ee787threading

Tff7b72import T7ee787numpy Tff7b72as T7ee787np
Tff7b72import T7ee787RNS
Tff7b72from T7ee787LXSTT7ee787.T7ee787Codecs Tff7b72import Te6edf3NullTb4b4b4, Te6edf3Raw
Tff7b72from T7ee787LXSTT7ee787.T7ee787Mixer Tff7b72import Te6edf3Mixer
Tff7b72from T7ee787LXSTT7ee787.T7ee787Pipeline Tff7b72import Te6edf3Pipeline
Tff7b72from T7ee787LXSTT7ee787.T7ee787Sinks Tff7b72import Te6edf3LocalSink
Tff7b72from T7ee787LXSTT7ee787.T7ee787Sources Tff7b72import Te6edf3LocalSource

Tff7b72from T7ee787.T7ee787telephone_manager Tff7b72import Te6edf3Tee


Tff7b72def Td2a8ff_log_debugTb4b4b4(Te6edf3msgTb4b4b4: Tffa657strTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Te6edf3msgTb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)


Tff7b72class T56d364WebAudioSourceTb4b4b4(Te6edf3LocalSourceTb4b4b4)Tb4b4b4:
T8b949e"""Injects PCM frames (int16 little-endian) received over websocket into the transmit mixer."""

Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3target_frame_msTb4b4b4: Tffa657intTb4b4b4, Te6edf3sinkTb4b4b4: Te6edf3MixerTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8fftarget_frame_ms Tff7b72= Te6edf3target_frame_ms Tff7b72or T79c0ff60
Tff7b72selfTff7b72.Td2a8ffsink Tff7b72= Te6edf3sink
Tff7b72selfTff7b72.Td2a8ffcodec Tff7b72= Te6edf3RawTb4b4b4(Te6edf3channelsTff7b72=T79c0ff1Tb4b4b4, Te6edf3bitdepthTff7b72=T79c0ff16Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffchannels Tff7b72= T79c0ff1
Tff7b72selfTff7b72.Td2a8ffsamplerate Tff7b72= T79c0ff48000
Tff7b72selfTff7b72.Td2a8ffbitdepth Tff7b72= T79c0ff16

Tff7b72def Td2a8ffstartTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e# Nothing to start; frames are pushed from the websocket thread.
Tff7b72pass

Tff7b72def Td2a8ffstopTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e# Nothing to stop; kept for interface compatibility.
Tff7b72pass

Tff7b72def Td2a8ffcan_receiveTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3from_sourceTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72True

Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3sourceTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
T8b949e# Not used; frames are pushed via push_pcm.
Tff7b72pass

Tff7b72def Td2a8ffpush_pcmTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pcm_bytesTb4b4b4: Tffa657bytesTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3samples Tff7b72= Tb4b4b4(
Te6edf3npTff7b72.Td2a8fffrombufferTb4b4b4(Te6edf3pcm_bytesTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8ffint16Tb4b4b4)Tff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4) Tff7b72/ T79c0ff32768.0
Tb4b4b4)
Tff7b72if Te6edf3samplesTff7b72.Td2a8ffsize Tff7b72== T79c0ff0Tb4b4b4:
Tff7b72return
Te6edf3samples Tff7b72= Te6edf3samplesTff7b72.Td2a8ffreshapeTb4b4b4(Tff7b72-T79c0ff1Tb4b4b4, T79c0ff1Tb4b4b4)
Te6edf3frame Tff7b72= Tff7b72selfTff7b72.Td2a8ffcodecTff7b72.Td2a8ffencodeTb4b4b4(Te6edf3samplesTb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ffsink Tff7b72and Tff7b72selfTff7b72.Td2a8ffsinkTff7b72.Td2a8ffcan_receiveTb4b4b4(Te6edf3from_sourceTff7b72=Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffsinkTff7b72.Td2a8ffhandle_frameTb4b4b4(Te6edf3frameTb4b4b4, Tff7b72selfTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4: T8b949e# noqa: BLE001
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffWebAudioSource: failed to push pcm: Tffd700{Te6edf3excTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)


Tff7b72class T56d364WebAudioSinkTb4b4b4(Te6edf3LocalSinkTb4b4b4)Tb4b4b4:
T8b949e"""Pushes received PCM frames to websocket clients."""

Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3loopTb4b4b4: Te6edf3asyncioTff7b72.Td2a8ffAbstractEventLoopTb4b4b4, Te6edf3send_bytesTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffloop Tff7b72= Te6edf3loop
Tff7b72selfTff7b72.Td2a8ffsend_bytes Tff7b72= Te6edf3send_bytes

Tff7b72def Td2a8ffcan_receiveTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3from_sourceTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72True

Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3sourceTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
T8b949e# frame is expected to be numpy float PCM from receive mixer
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3frameTb4b4b4, Ta5d6ff"Ta5d6ffastypeTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3samples Tff7b72= Te6edf3npTff7b72.Td2a8ffclipTb4b4b4(Te6edf3frameTb4b4b4, Tff7b72-T79c0ff1.0Tb4b4b4, T79c0ff1.0Tb4b4b4)Tff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3pcm Tff7b72= Tb4b4b4(Te6edf3samples Tff7b72* T79c0ff32767.0Tb4b4b4)Tff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8ffint16Tb4b4b4)Tff7b72.Td2a8fftobytesTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3pcm Tff7b72= Te6edf3frame
Tff7b72selfTff7b72.Td2a8ffloopTff7b72.Td2a8ffcall_soon_threadsafeTb4b4b4(Te6edf3asyncioTff7b72.Td2a8ffcreate_taskTb4b4b4, Tff7b72selfTff7b72.Td2a8ffsend_bytesTb4b4b4(Te6edf3pcmTb4b4b4)Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4: T8b949e# noqa: BLE001
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffWebAudioSink: failed to handle frame: Tffd700{Te6edf3excTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)


Tff7b72class T56d364WebAudioBridgeTb4b4b4:
T8b949e"""Coordinates websocket audio transport with an active LXST telephone call."""

Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3telephone_managerTb4b4b4, Te6edf3config_managerTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8fftelephone_manager Tff7b72= Te6edf3telephone_manager
Tff7b72selfTff7b72.Td2a8ffconfig_manager Tff7b72= Te6edf3config_manager
Tff7b72selfTff7b72.Td2a8ffclients Tff7b72= Tffa657setTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fftx_sourceTb4b4b4: Te6edf3WebAudioSource Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffrx_sinkTb4b4b4: Te6edf3WebAudioSink Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffrx_teeTb4b4b4: Te6edf3Tee Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_loop Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8fflock Tff7b72= Te6edf3threadingTff7b72.Td2a8ffLockTb4b4b4(Tb4b4b4)

Tf0883e@property
Tff7b72def Td2a8ffloopTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_loopTb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ff_loop

Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_loop Tff7b72= Te6edf3asyncioTff7b72.Td2a8ffget_running_loopTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149RuntimeErrorTb4b4b4:
T8b949e# Fallback to finding it via AsyncUtils if possible
Tff7b72from T7ee787.T7ee787async_utils Tff7b72import Te6edf3AsyncUtils

Tff7b72selfTff7b72.Td2a8ff_loop Tff7b72= Te6edf3AsyncUtilsTff7b72.Td2a8ffmain_loop

Tff7b72return Tff7b72selfTff7b72.Td2a8ff_loop

Tff7b72def Td2a8ff_teleTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tffa657getattrTb4b4b4(Tff7b72selfTff7b72.Td2a8fftelephone_managerTb4b4b4, Ta5d6ff"Ta5d6fftelephoneTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)

Tff7b72def Td2a8ffconfig_enabledTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4(
Tff7b72selfTff7b72.Td2a8ffconfig_manager
Tff7b72and Tffa657hasattrTb4b4b4(Tff7b72selfTff7b72.Td2a8ffconfig_managerTb4b4b4, Ta5d6ff"Ta5d6fftelephone_web_audio_enabledTa5d6ff"Tb4b4b4)
Tff7b72and Tff7b72selfTff7b72.Td2a8ffconfig_managerTff7b72.Td2a8fftelephone_web_audio_enabledTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tb4b4b4)

Tff7b72def Td2a8ffallow_fallbackTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4(
Tff7b72selfTff7b72.Td2a8ffconfig_manager
Tff7b72and Tffa657hasattrTb4b4b4(Tff7b72selfTff7b72.Td2a8ffconfig_managerTb4b4b4, Ta5d6ff"Ta5d6fftelephone_web_audio_allow_fallbackTa5d6ff"Tb4b4b4)
Tff7b72and Tff7b72selfTff7b72.Td2a8ffconfig_managerTff7b72.Td2a8fftelephone_web_audio_allow_fallbackTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tb4b4b4)

Tff7b72def Td2a8ffattach_clientTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3clientTb4b4b4)Tb4b4b4:
Tff7b72with Tff7b72selfTff7b72.Td2a8fflockTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffclientsTff7b72.Td2a8ffaddTb4b4b4(Te6edf3clientTb4b4b4)
Te6edf3tele Tff7b72= Tff7b72selfTff7b72.Td2a8ff_teleTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3tele Tff7b72or Tff7b72not Te6edf3teleTff7b72.Td2a8ffactive_callTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72selfTff7b72.Td2a8ff_ensure_remote_txTb4b4b4(Te6edf3teleTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_rx_teeTb4b4b4(Te6edf3teleTb4b4b4)
Tff7b72return Tff7b72True

Tff7b72def Td2a8ffdetach_clientTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3clientTb4b4b4)Tb4b4b4:
Tff7b72with Tff7b72selfTff7b72.Td2a8fflockTb4b4b4:
Tff7b72if Te6edf3client Tff7b72in Tff7b72selfTff7b72.Td2a8ffclientsTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffclientsTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3clientTb4b4b4)
Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ffclients Tff7b72and Tff7b72selfTff7b72.Td2a8ffallow_fallbackTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_restore_host_audioTb4b4b4(Tb4b4b4)

Tff7b72async Tff7b72def Td2a8ffsend_statusTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3clientTb4b4b4)Tb4b4b4:
Te6edf3tele Tff7b72= Tff7b72selfTff7b72.Td2a8ff_teleTb4b4b4(Tb4b4b4)
Te6edf3frame_ms Tff7b72= Tffa657getattrTb4b4b4(Te6edf3teleTb4b4b4, Ta5d6ff"Ta5d6fftarget_frame_time_msTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4) Tff7b72or T79c0ff60
Tff7b72await Te6edf3clientTff7b72.Td2a8ffsend_strTb4b4b4(
Te6edf3jsonTff7b72.Td2a8ffdumpsTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffweb_audio.readyTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffframe_msTa5d6ff"Tb4b4b4: Te6edf3frame_msTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8ffpush_client_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pcm_bytesTb4b4b4: Tffa657bytesTb4b4b4)Tb4b4b4:
Tff7b72with Tff7b72selfTff7b72.Td2a8fflockTb4b4b4:
Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8fftx_sourceTb4b4b4:
Tff7b72return
Tff7b72selfTff7b72.Td2a8fftx_sourceTff7b72.Td2a8ffpush_pcmTb4b4b4(Te6edf3pcm_bytesTb4b4b4)

Tff7b72async Tff7b72def Td2a8ff_send_bytes_to_allTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pcm_bytesTb4b4b4: Tffa657bytesTb4b4b4)Tb4b4b4:
Te6edf3stale Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3ws Tff7b72in Tffa657listTb4b4b4(Tff7b72selfTff7b72.Td2a8ffclientsTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72await Te6edf3wsTff7b72.Td2a8ffsend_bytesTb4b4b4(Te6edf3pcm_bytesTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Te6edf3staleTff7b72.Td2a8ffappendTb4b4b4(Te6edf3wsTb4b4b4)
Tff7b72for Te6edf3ws Tff7b72in Te6edf3staleTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdetach_clientTb4b4b4(Te6edf3wsTb4b4b4)

Tff7b72def Td2a8ff_ensure_remote_txTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3teleTb4b4b4)Tb4b4b4:
T8b949e# Rebuild transmit path with websocket-backed source
Tff7b72if Tff7b72selfTff7b72.Td2a8fftx_sourceTb4b4b4:
Tff7b72return
Tff7b72tryTb4b4b4:
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3teleTb4b4b4, Ta5d6ff"Ta5d6ffaudio_inputTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3teleTff7b72.Td2a8ffaudio_inputTb4b4b4:
Te6edf3teleTff7b72.Td2a8ffaudio_inputTff7b72.Td2a8ffstopTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fftx_source Tff7b72= Te6edf3WebAudioSourceTb4b4b4(
Te6edf3target_frame_msTff7b72=Tffa657getattrTb4b4b4(Te6edf3teleTb4b4b4, Ta5d6ff"Ta5d6fftarget_frame_time_msTa5d6ff"Tb4b4b4, T79c0ff60Tb4b4b4)Tb4b4b4,
Te6edf3sinkTff7b72=Te6edf3teleTff7b72.Td2a8fftransmit_mixerTb4b4b4,
Tb4b4b4)
Te6edf3teleTff7b72.Td2a8ffaudio_input Tff7b72= Tff7b72selfTff7b72.Td2a8fftx_source
Tff7b72if Te6edf3teleTff7b72.Td2a8fftransmit_mixer Tff7b72and Tff7b72not Te6edf3teleTff7b72.Td2a8fftransmit_mixerTff7b72.Td2a8ffshould_runTb4b4b4:
Te6edf3teleTff7b72.Td2a8fftransmit_mixerTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4: T8b949e# noqa: BLE001
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffWebAudioBridge: failed to swap transmit path: Tffd700{Te6edf3excTffd700}Ta5d6ff"Tb4b4b4,
Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4,
Tb4b4b4)

Tff7b72def Td2a8ff_ensure_rx_teeTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3teleTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ffrx_sinkTb4b4b4:
Tff7b72return
Tff7b72tryTb4b4b4:
Te6edf3send_fn Tff7b72= Tff7b72lambda Te6edf3pcmTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_send_bytes_to_allTb4b4b4(Te6edf3pcmTb4b4b4) T8b949e# noqa: E731
Tff7b72selfTff7b72.Td2a8ffrx_sink Tff7b72= Te6edf3WebAudioSinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffloopTb4b4b4, Te6edf3send_fnTb4b4b4)
T8b949e# Build tee with existing audio_output as first sink to preserve speaker
Te6edf3base_sink Tff7b72= Te6edf3teleTff7b72.Td2a8ffaudio_output
Tff7b72selfTff7b72.Td2a8ffrx_tee Tff7b72= Te6edf3TeeTb4b4b4(Te6edf3base_sinkTb4b4b4) Tff7b72if Te6edf3base_sink Tff7b72else Te6edf3TeeTb4b4b4(Tff7b72selfTff7b72.Td2a8ffrx_sinkTb4b4b4)
Tff7b72if Te6edf3base_sinkTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffrx_teeTff7b72.Td2a8ffadd_sinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffrx_sinkTb4b4b4)
Te6edf3teleTff7b72.Td2a8ffaudio_output Tff7b72= Tff7b72selfTff7b72.Td2a8ffrx_tee
Tff7b72if Te6edf3teleTff7b72.Td2a8ffreceive_pipelineTb4b4b4:
Te6edf3teleTff7b72.Td2a8ffreceive_pipelineTff7b72.Td2a8ffstopTb4b4b4(Tb4b4b4)
Te6edf3teleTff7b72.Td2a8ffreceive_pipeline Tff7b72= Te6edf3PipelineTb4b4b4(
Te6edf3sourceTff7b72=Te6edf3teleTff7b72.Td2a8ffreceive_mixerTb4b4b4,
Te6edf3codecTff7b72=Te6edf3NullTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3sinkTff7b72=Tff7b72selfTff7b72.Td2a8ffrx_teeTb4b4b4,
Tb4b4b4)
Te6edf3teleTff7b72.Td2a8ffreceive_pipelineTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4: T8b949e# noqa: BLE001
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffWebAudioBridge: failed to tee receive path: Tffd700{Te6edf3excTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_ERRORTb4b4b4)

Tff7b72def Td2a8ff_restore_host_audioTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3tele Tff7b72= Tff7b72selfTff7b72.Td2a8ff_teleTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3teleTb4b4b4:
Tff7b72return
Tff7b72tryTb4b4b4:
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3teleTb4b4b4, Ta5d6ff"Ta5d6ff_Telephony__reconfigure_transmit_pipelineTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3teleTff7b72.Td2a8ff_Telephony__reconfigure_transmit_pipelineTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72pass
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3teleTff7b72.Td2a8ffreceive_pipelineTb4b4b4:
Te6edf3teleTff7b72.Td2a8ffreceive_pipelineTff7b72.Td2a8ffstopTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3teleTff7b72.Td2a8ffaudio_output Tff7b72and Tff7b72selfTff7b72.Td2a8ffrx_teeTb4b4b4:
T8b949e# If tee had original sink as first element, revert
Te6edf3primary Tff7b72= Tff7b72selfTff7b72.Td2a8ffrx_teeTff7b72.Td2a8ffsinksTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72if Tff7b72selfTff7b72.Td2a8ffrx_teeTff7b72.Td2a8ffsinks Tff7b72else Tff7b72None
Tff7b72if Te6edf3primary Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3teleTff7b72.Td2a8ffaudio_output Tff7b72= Te6edf3primary
Tff7b72if Te6edf3teleTff7b72.Td2a8ffreceive_mixerTb4b4b4:
Te6edf3teleTff7b72.Td2a8ffreceive_pipeline Tff7b72= Te6edf3PipelineTb4b4b4(
Te6edf3sourceTff7b72=Te6edf3teleTff7b72.Td2a8ffreceive_mixerTb4b4b4,
Te6edf3codecTff7b72=Te6edf3NullTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3sinkTff7b72=Te6edf3teleTff7b72.Td2a8ffaudio_outputTb4b4b4,
Tb4b4b4)
Te6edf3teleTff7b72.Td2a8ffreceive_pipelineTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72pass
Tff7b72selfTff7b72.Td2a8fftx_source Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffrx_sink Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffrx_tee Tff7b72= Tff7b72None

Tff7b72def Td2a8ffon_call_endedTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72with Tff7b72selfTff7b72.Td2a8fflockTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffclientsTff7b72.Td2a8ffclearTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fftx_source Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffrx_sink Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ffrx_tee Tff7b72= Tff7b72None


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────